module Geometry.FPlaneVisibility ( VisibilityMoment
                                 , visibilityMoment 
                                 , evolutionVisibility 
                                 , optimizeAngle 
                                 , visibleFilter ) where

import Data.List (sortBy, maximumBy)
import qualified Data.IntMap as M
import Geometry.Intersection

type VisibilityMoment = (Angle, Bool)

visibilityMoment :: Point -> Polygon -> [VisibilityMoment]
visibilityMoment p polygon = f zones where
  zones = pointZones p polygon
  f (InVisible) = []
  f (Visible)   = [(0, True)]
  f (Arc xs) = concatMap (\(a0,a1) -> if (a0 > a1)
                                      then [(0, True), (a1, False), (a0, True)]
                                      else [(a0, True), (a1, False)]) xs

evolutionVisibility :: [(Int, Point)] -> [Polygon] -> [(Angle, M.IntMap Point)]
evolutionVisibility points polygons = zip angles $ tail $ scanl (\x f -> f x) M.empty cmd 
  where
    cmd = map snd ts
    angles = map fst ts
    ts = sortBy (\(a,_) (b,_) -> compare a b) $ 
         [ case v of 
              True  -> (a, M.insert i p)
              False -> (a, M.delete i)
         | (i,p) <- points, pp <- polygons, (a,v) <- visibilityMoment p pp ]
  
optimizeAngle :: [(Int, Point)] -> [Polygon] -> Maybe (Angle, [(Int, Point)])
optimizeAngle points polygons = case evolutionVisibility points polygons of
  [] -> Nothing
  xs -> let (a,e) = maximumBy (\(_, e1) (_, e2) -> compare (M.size e1) (M.size e2)) xs
        in Just (a, M.assocs e)
      
visibleFilter :: [(Int, Point)] -> [Polygon] -> [(Int, Point)]
visibleFilter points polygons = [(i,p) | ps <- polygons, (i,p) <- points, inPolygon ps p]

